// Drop 释放资源
// 一拳打跑 GC 的同时一脚踢翻手动资源回收
// 主要就归功于 Drop 特征，同时它也是智能指针的必备特征之一。

// 指定在一个变量超出作用域时，执行一段特定的代码，最终编译器将帮你自动插入这段收尾代码
#[cfg(test)]
mod drop {
    struct HasDrop1;

    struct HasDrop2;

    impl Drop for HasDrop1 {
        fn drop(&mut self) {
            println!("Dropping HasDrop1!");
        }
    }

    impl Drop for HasDrop2 {
        fn drop(&mut self) {
            println!("Dropping HasDrop2!");
        }
    }

    struct HasTwoDrops {
        one: HasDrop1,
        two: HasDrop2,
    }

    impl Drop for HasTwoDrops {
        fn drop(&mut self) {
            println!("Dropping HasTwoDrops!");
        }
    }

    struct Foo;

    impl Drop for Foo {
        fn drop(&mut self) {
            println!("Dropping Foo!")
        }
    }

    #[test]
    fn main() {
        /*
            结构体中每个字段都有自己的 Drop
        Drop 的顺序
            变量级别，按照逆序(栈)的方式（go defer），_x 在 _foo 之前创建，因此 _x 在 _foo 之后被 drop
            结构体内部，按照顺序的方式，结构体 _x 中的字段按照 定义中(struct 声明处) 的顺序依次 drop
        */
        let _x = HasTwoDrops {
            two: HasDrop2,
            one: HasDrop1,
        };
        println!("============!");
        // Rust 自动为几乎所有类型都实现了 Drop 特征
        let _foo = Foo;
        println!("Running!");
    }
}

#[cfg(test)]
mod drop_ {
    // #[derive(Copy)] // 互斥
    // 实现了 Copy 的特征会被编译器隐式的复制，因此非常难以预测析构函数执行的时间和频率。
    // 因此这些实现了 Copy 的类型无法拥有析构函数
    #[derive(Debug)]
    struct Foo;

    impl Drop for Foo {
        fn drop(&mut self) {
            println!("Dropping Foo!")
        }
    }

    impl Foo {
        fn run(self) {
            println!("run")
        }
    }

    #[test]
    fn main() {
        let foo = Foo;
        // foo.drop(); // 同时拿走了所有权
        // std::mem::drop(foo);
        println!("Running!:{:?}", foo);
        foo.run();
    }
}
/*
Drop 使用场景
对于 Drop 而言，主要有两个功能：

    回收内存资源
    执行一些收尾工作
我们都无需手动去 drop 以回收内存资源，因为 Rust 会自动帮我们完成这些工作，
它甚至会对复杂类型的每个字段都单独的调用 drop 进行回收！

但是确实有极少数情况，需要你自己来回收资源的，
例如文件描述符、网络 socket 等，当这些值超出作用域不再使用时，就需要进行关闭以释放相关的资源，
在这些情况下，就需要使用者自己来解决 Drop 的问题。
*/
